﻿#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using JigLibX.Collision;
using JigLibX.Physics;
using JigLibX.Geometry;
using JigLibX.Math;
using Microsoft.Xna.Framework.Graphics;
using JigLibX.Utils;
using SqEngine.Components;
using sqengine.Components;
using sqengine.Engine;
using sqengine.Engine.Common;
#endregion

namespace sqengine.PhysicObjects
{
    public class HeightmapObject : PhysicObject
    {

        Game _game;
        Camera _camera;
        Texture2D terrain_texture, day_texture, night_texture, sunset_texture;
        Effect _sky_effect;
        SkyDome _skydome;
        AdvancedContent _adcontent;
        bool _have_texure;


        public HeightmapObject(Game game, Model model, Vector2 shift, Camera camera, AdvancedContent adcontent, string t_texure)
            : base(game, model)
        {
            _game = game;
            _camera = camera;
            body = new Body(); // just a dummy. The PhysicObject uses its position to get the draw pos
            collision = new CollisionSkin(null);
            _adcontent = adcontent;

            HeightMapInfo heightMapInfo = model.Tag as HeightMapInfo;
            Array2D field = new Array2D(heightMapInfo.heights.GetUpperBound(0), heightMapInfo.heights.GetUpperBound(1));

            for (int x = 0; x < heightMapInfo.heights.GetUpperBound(0); x++)
            {
                for (int z = 0; z < heightMapInfo.heights.GetUpperBound(1); z++)
                {
                    field.SetAt(x, z, heightMapInfo.heights[x, z]);
                }
            }


            if (_adcontent != null)
            {
                terrain_texture = adcontent.LoadTexture2D(t_texure);
                _have_texure = true;
            }

            // move the body. The body (because its not connected to the collision
            // skin) is just a dummy. But the base class shoudl know where to
            // draw the model.
            body.MoveTo(new Vector3(shift.X, 0, shift.Y), Matrix.Identity);


            collision.AddPrimitive(new Heightmap(field, shift.X, shift.Y, 1, 1), new MaterialProperties(0.7f, 0.7f, 0.6f));

            PhysicsSystem.CurrentPhysicsSystem.CollisionSystem.AddCollisionSkin(collision);


        }

        public void SetTexture(Texture2D texture)
        {

            terrain_texture = texture;
        }

        public void SetModel(Model _model)
        {

            model = _model;
        }

        public void SetSkydome(SkyDome skydome, Texture2D day, Texture2D sunset, Texture2D night, Effect sky_effect)
        {
            _skydome = skydome;
            day_texture = day;
            sunset_texture = sunset;
            night_texture = night;
            _sky_effect = sky_effect;
            CustomEffect = true;
            _sky_effect.CurrentTechnique = _sky_effect.Techniques["SkyDome"];
            RemapModel(model, _sky_effect);
        }

        public override void ApplyEffects(BasicEffect effect)
        {
            if (!CustomEffect)
            {
                effect.PreferPerPixelLighting = true;

                if (_have_texure)
                {
                    effect.Texture = terrain_texture;
                    effect.TextureEnabled = true;
                }
                effect.LightingEnabled = true;

                effect.DiffuseColor = new Vector3(1f);
                effect.AmbientLightColor = new Vector3(0.5f);

                effect.DirectionalLight0.Enabled = true;
                effect.DirectionalLight0.DiffuseColor = Vector3.One;


                effect.FogEnabled = true;
                effect.FogStart = 0;
                effect.FogEnd = 500;
                effect.FogColor = Color.CornflowerBlue.ToVector3();
            }



        }

        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);


        }
        public override void Draw(GameTime gameTime)
        {

            if (CustomEffect)
            {
                DrawTerrain(gameTime);
            }
            base.Draw(gameTime);
        }

        public static void RemapModel(Model model, Effect effect)
        {
            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (ModelMeshPart part in mesh.MeshParts)
                {
                    part.Effect = effect;
                }
            }
        }

        private void DrawTerrain(GameTime gameTime)
        {
            Matrix View = _camera.View;
            Matrix Projection = _camera.Projection;
            RemapModel(model, _sky_effect);

            foreach (ModelMesh mesh in model.Meshes)
            {
                //Matrix World = body.Orientation;

                Matrix World = body.Orientation;
                Matrix WorldIT = Matrix.Invert(World);
                WorldIT = Matrix.Transpose(WorldIT);

                foreach (Effect effect in mesh.Effects)
                {
                    effect.Parameters["WorldIT"].SetValue(WorldIT);
                    effect.Parameters["WorldViewProj"].SetValue(World * View * Projection);
                    effect.Parameters["ViewInv"].SetValue(Matrix.Invert(View));
                    effect.Parameters["World"].SetValue(World);

                    if (_have_texure)
                        effect.Parameters["DiffuseTexture"].SetValue(terrain_texture);
                    
                    effect.Parameters["SkyTextureNight"].SetValue(night_texture);
                    effect.Parameters["SkyTextureSunset"].SetValue(sunset_texture);
                    effect.Parameters["SkyTextureDay"].SetValue(day_texture);

                    effect.Parameters["isSkydome"].SetValue(false);

                    effect.Parameters["LightDirection"].SetValue(-_skydome.Parameters.LightDirection);
                    effect.Parameters["LightColor"].SetValue(_skydome.Parameters.LightColor);
                    effect.Parameters["LightColorAmbient"].SetValue(_skydome.Parameters.LightColorAmbient);
                    effect.Parameters["FogColor"].SetValue(_skydome.Parameters.FogColor);
                    effect.Parameters["fDensity"].SetValue(0.0003f);
                    effect.Parameters["SunLightness"].SetValue(_skydome.Parameters.SunLightness);
                    effect.Parameters["sunRadiusAttenuation"].SetValue(_skydome.Parameters.SunRadiusAttenuation);
                    effect.Parameters["largeSunLightness"].SetValue(_skydome.Parameters.LargeSunLightness);
                    effect.Parameters["largeSunRadiusAttenuation"].SetValue(_skydome.Parameters.LargeSunRadiusAttenuation);
                    effect.Parameters["dayToSunsetSharpness"].SetValue(_skydome.Parameters.DayToSunsetSharpness);
                    effect.Parameters["hazeTopAltitude"].SetValue(_skydome.Parameters.HazeTopAltitude);

                }
                mesh.Draw();
            }
        }


    }
}
